﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Xml.Linq;
using DotNetX;
using RPGX.Server.Game;
using RPGXEngine.Networking;

namespace RPGX.Server.Network
{
    public class NetworkManager
    {
        #region Properties

        public Server Server
        {
            get { return _server; }
            set { _server = value; }
        }
        private Server _server = null;

        public int Port
        {
            get { return _port; }
            set { _port = value; }
        }
        private int _port = 0;

        public TcpListener TcpServer
        {
            get { return _tcpServer; }
            set { _tcpServer = value; }
        }
        private TcpListener _tcpServer = null;

        public Thread ThreadListener
        {
            get { return _threadListener; }
            set { _threadListener = value; }
        }
        private Thread _threadListener = null;

        public bool IsRunning
        {
            get { lock (this.IsRunningLock) { return _isRunning; }  }
            set { lock (this.IsRunningLock) { _isRunning = value; }  }
        }
        private bool _isRunning = true;
        private object IsRunningLock = new object();

        public List<NetworkMessage> MessageQueue
        {
            get { lock (this.MessageQueueLock) { return _messageQueue; }  }
            set { lock (this.MessageQueueLock) { _messageQueue = value; } }
        }
        private List<NetworkMessage> _messageQueue = new List<NetworkMessage>();
        private object MessageQueueLock = new object();

        #endregion

        #region Public Methods

        public void Load(string settingsFileName, Server server)
        {
            this.UnLoad();

            this.IsRunning = true;

            this.Server = server;

            this.LoadSettings(settingsFileName);

            this.TcpServer = new TcpListener(IPAddress.Any, this.Port);
            this.ThreadListener = new Thread(this.ThreadListenerMethod);
            this.ThreadListener.Start();
        }

        public void UnLoad()
        {
            this.IsRunning = false;

            if (this.ThreadListener != null)
            {
                this.ThreadListener.Abort();
                this.ThreadListener = null;
            }

            if (this.TcpServer != null)
            {
                this.TcpServer.Stop();
                this.TcpServer = null;
            }

            this.Port = 0;
        }

        public void Update()
        {
            this.SendMessages();
        }

        public void SendMessage(NetworkMessage m)
        {
            this.MessageQueue.Add(m);
        }

        #endregion

        #region Private Methods

        private void LoadSettings(string settingsFileName)
        {
            XDocument doc = XDocument.Load(settingsFileName);

            this.Port = doc.Element("settings").Element("network").Element("port").Value.ToInt32OrZero();
        }

        private void SendMessages()
        {
            List<GameClient> clients = new List<GameClient>();

            foreach(NetworkMessage m in this.MessageQueue)
            {
                clients.Clear();

                if (m.DestinationInformation.DestinationType == ClientDestinationInfomation.DestinationTypes.Server)
                {
                    // we won't send a message to ourself...
                    continue;
                }
                else if (m.DestinationInformation.DestinationType == ClientDestinationInfomation.DestinationTypes.AllClients)
                {
                    clients.AddRange(ClientPool.GameClients.Values);
                }
                else if (m.DestinationInformation.DestinationType == ClientDestinationInfomation.DestinationTypes.Team)
                {
                }
                else if (m.DestinationInformation.DestinationType == ClientDestinationInfomation.DestinationTypes.Client)
                {
                    if (m.DestinationInformation.Id == 0 || !ClientPool.GameClients.ContainsKey(m.DestinationInformation.Id))
                        continue;

                    clients.Add(ClientPool.GameClients[m.DestinationInformation.Id]);
                }

                foreach (var c in clients)
                {
                    c.SendMessage(m);
                }
            }

            this.MessageQueue.Clear();
        }

        #endregion

        #region Thread Methods

        private void ThreadListenerMethod()
        {
            this.TcpServer.Start();

            while (this.IsRunning)
            {
                TcpClient c = this.TcpServer.AcceptTcpClient();

                GameClient gc = new GameClient(c, this);
            }

            this.TcpServer.Stop();
        }

        #endregion
    }
}
